This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / web / src / routes / [handle] / [repo] / +page.ts
3.4 kB 96 lines
1import { createBobbinClient } from "$lib/api/client"; 2import { languages as knotLanguages, tree as knotTree } from "$lib/api/knot"; 3import { parallel } from "$lib/api/load"; 4import { 5 branchesFor, 6 logFor, 7 sortTreeEntries, 8 tagsByCommitHash, 9 tagsFor, 10 toBranchSummary, 11 toCommitSummary, 12 toTagSummary, 13 toTreeEntrySummary 14} from "$lib/api/repo"; 15import type { LanguageSlice } from "$lib/components/repo/types"; 16import type { PageLoad } from "./$types"; 17 18const COMMIT_LIMIT = 10; 19const BRANCH_LIMIT = 5; 20const TAG_LIMIT = 5; 21// knots cap ref listings at 100, so a total is really an "at least" 22const REF_LIMIT = 100; 23 24const orNull = <T>(promise: Promise<T>): Promise<T | null> => promise.catch(() => null); 25 26const toLanguageSlices = (languages: { name: string; size: number }[]): LanguageSlice[] => { 27 const sized = languages.filter((language) => language.size > 0); 28 const total = sized.reduce((sum, language) => sum + language.size, 0); 29 if (total === 0) return []; 30 31 const slices = sized.map((language) => { 32 const share = (language.size / total) * 100; 33 return { name: language.name, share, percentage: Math.floor(share) }; 34 }); 35 36 const short = 100 - slices.reduce((sum, slice) => sum + slice.percentage, 0); 37 [...slices] 38 .sort((a, b) => (b.share % 1) - (a.share % 1) || b.share - a.share) 39 .slice(0, Math.max(0, short)) 40 .forEach((slice) => { 41 slice.percentage += 1; 42 }); 43 44 return slices.sort((a, b) => b.share - a.share); 45}; 46 47export const load: PageLoad = async (event) => { 48 const parent = await event.parent(); 49 const ctx = createBobbinClient({ serviceUrl: parent.publicConfig.bobbinUrl, fetch: event.fetch }); 50 const repo = parent.repo.uri; 51 const ref = parent.repo.defaultBranch; 52 53 // every list falls back on its own so a partial page still renders 54 const results = await parallel({ 55 tree: orNull(knotTree(ctx, { repo, ref })), 56 log: orNull(logFor(ctx, repo, ref, COMMIT_LIMIT)), 57 branches: orNull(branchesFor(ctx, repo, REF_LIMIT)), 58 tags: orNull(tagsFor(ctx, repo, REF_LIMIT)), 59 languages: orNull(knotLanguages(ctx, { repo, ref })) 60 }); 61 62 const branches = (results.branches?.branches ?? []).map(toBranchSummary); 63 const tags = (results.tags?.tags ?? []).map(toTagSummary); 64 const commits = (results.log?.commits ?? []).map(toCommitSummary); 65 const files = sortTreeEntries((results.tree?.files ?? []).map(toTreeEntrySummary)); 66 67 const languages = toLanguageSlices(results.languages?.languages ?? []); 68 69 // nothing answered, so the knot is down or doesn't know this repo 70 const knotUnreachable = 71 results.tree === null && results.log === null && results.branches === null; 72 // the knot answered but there is nothing there, so it was never pushed to 73 const isEmpty = !knotUnreachable && files.length === 0 && branches.length === 0; 74 75 return { 76 ref, 77 isEmpty, 78 knotUnreachable, 79 files, 80 readme: results.tree?.readme ?? null, 81 commits, 82 tagsByCommit: tagsByCommitHash(commits, tags), 83 totalCommits: results.log?.total ?? commits.length, 84 branches: branches.slice(0, BRANCH_LIMIT), 85 totalBranches: branches.length, 86 tags: tags.slice(0, TAG_LIMIT), 87 totalTags: tags.length, 88 // the switcher needs every ref, not just the visible slice 89 refs: { 90 branches: branches.map((branch) => branch.name), 91 tags: tags.map((tag) => tag.name), 92 capped: branches.length >= REF_LIMIT || tags.length >= REF_LIMIT 93 }, 94 languages 95 }; 96};